home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1996 July: Mac OS SDK / Dev.CD Jul 96 SDK / Dev.CD Jul 96 SDK1.toast / Development Kits (Disc 1) / OpenDoc Development Framework / ODFDev / ODF / Framewrk / FWPart / Sources / FWLnkDst.cpp < prev    next >
Encoding:
Text File  |  1996-04-25  |  13.2 KB  |  432 lines  |  [TEXT/MPS ]

  1. //========================================================================================
  2. //
  3. //    File:                FWLnkDst.cpp
  4. //    Release Version:    $ ODF 1 $
  5. //
  6. //    Copyright:    (c) 1993 - 1996 by Apple Computer, Inc., all rights reserved.
  7. //
  8. //========================================================================================
  9.  
  10. #include "FWFrameW.hpp"
  11.  
  12. #ifndef FWLNKDST_H
  13. #include "FWLnkDst.h"
  14. #endif
  15.  
  16. // ----- Framework Includes -----
  17.  
  18. #ifndef FWPART_H
  19. #include "FWPart.h"
  20. #endif
  21.  
  22. #ifndef FWPRESEN_H
  23. #include "FWPresen.h"
  24. #endif
  25.  
  26. #ifndef FWLNKITE_H
  27. #include "FWLnkIte.h"
  28. #endif
  29.  
  30. #ifndef FWCLNINF_H
  31. #include "FWClnInf.h"
  32. #endif
  33.  
  34. #ifndef FWINTER_H
  35. #include "FWInter.h"
  36. #endif
  37.  
  38. // ----- Foundation Includes -----
  39.  
  40. #ifndef FWPRIDEB_H
  41. #include "FWPriDeb.h"
  42. #endif
  43.  
  44. #ifndef FWBARRAY_H
  45. #include "FWBArray.h"
  46. #endif
  47.  
  48. // ----- OpenDoc Includes -----
  49.  
  50. #ifndef SOM_Module_OpenDoc_StdProps_defined
  51. #include <StdProps.xh>
  52. #endif
  53.  
  54. #ifndef SOM_Module_OpenDoc_StdTypes_defined
  55. #include <StdTypes.xh>
  56. #endif
  57.  
  58. #ifndef SOM_ODStorageUnit_xh
  59. #include <StorageU.xh>
  60. #endif
  61.  
  62. #ifndef SOM_ODSession_xh
  63. #include <ODSessn.xh>
  64. #endif
  65.  
  66. #ifndef SOM_ODLink_xh
  67. #include <Link.xh>
  68. #endif
  69.  
  70. //========================================================================================
  71. //    Runtime information
  72. //========================================================================================
  73.  
  74. #ifdef FW_BUILD_MAC
  75. #pragma segment odflinking
  76. #endif
  77.  
  78. //========================================================================================
  79. //    Template Instantiations
  80. //========================================================================================
  81.  
  82. FW_DEFINE_AUTO_TEMPLATE(FW_TOrderedCollectionIterator, FW_CLinkDestination)
  83. FW_DEFINE_AUTO_TEMPLATE(FW_TOrderedCollection, FW_CLinkDestination)
  84.  
  85. #ifdef FW_USE_TEMPLATE_PRAGMAS
  86.  
  87. #pragma template_access public
  88. #pragma template FW_TOrderedCollection<FW_CLinkDestination>
  89. #pragma template FW_TOrderedCollectionIterator<FW_CLinkDestination>
  90.  
  91. #endif
  92.  
  93. //========================================================================================
  94. //    class FW_CLinkDestination
  95. //========================================================================================
  96.  
  97. //----------------------------------------------------------------------------------------
  98. //    FW_CLinkDestination::FW_CLinkDestination
  99. //----------------------------------------------------------------------------------------
  100.  
  101. FW_CLinkDestination::FW_CLinkDestination(Environment* ev, 
  102.                                          ODLink* odLink, 
  103.                                          ODLinkInfo* linkInfo, 
  104.                                          FW_CPresentation* presentation)
  105. :    FW_CLink(ev, presentation),
  106.     fODLink(NULL),
  107.     fRegistered(FALSE),
  108.     fPart(NULL),
  109.     fEstablished(false),
  110.     fEmbed(FALSE),
  111.     fDataInterchange(presentation->GetPart(ev)->GetDataInterchange(ev))
  112. {
  113.     if (odLink)
  114.     {
  115.         fODLink = odLink;
  116.         odLink->Acquire(ev);
  117.     }
  118.  
  119.     // Copy link info
  120.     fLinkInfo = *linkInfo;
  121. }
  122.  
  123. //----------------------------------------------------------------------------------------
  124. //    FW_CLinkDestination::~FW_CLinkDestination
  125. //----------------------------------------------------------------------------------------
  126.  
  127. FW_CLinkDestination::~FW_CLinkDestination()
  128. {
  129.     FW_SOMEnvironment ev;
  130.     this->Unregister(ev);
  131.     if (fODLink)
  132.         fODLink->Release(ev);
  133.  
  134.     if (fEmbed)                // fEmbedInfo is valid
  135.     {
  136.         //-- Dispose OpenDoc strings
  137.         if (fEmbedInfo.selectedKind != kODNULL)
  138.             ODDisposePtr(fEmbedInfo.selectedKind);
  139.         if (fEmbedInfo.translateKind != kODNULL)
  140.             ODDisposePtr(fEmbedInfo.translateKind);
  141.         if (fEmbedInfo.editor != kODNULL)
  142.             ODDisposePtr(fEmbedInfo.editor);
  143.     }
  144. }
  145.  
  146. //----------------------------------------------------------------------------------------
  147. //    FW_CLinkDestination::PrivEstablishLink
  148. //----------------------------------------------------------------------------------------
  149.  
  150. void FW_CLinkDestination::PrivEstablishLink(Environment* ev)
  151. {
  152.     this->LinkEstablished(ev);
  153.     fEstablished = true;
  154. }
  155.  
  156. //----------------------------------------------------------------------------------------
  157. //    FW_CLinkDestination::LinkEstablished
  158. //---------------------------------------------------------------------------------------
  159. void FW_CLinkDestination::LinkEstablished(Environment* ev)
  160. {
  161. FW_UNUSED(ev);
  162.     // Override to change the status of embedded frames to kODInLinkDestination
  163. }
  164.  
  165. //----------------------------------------------------------------------------------------
  166. //    FW_CLinkDestination::LinkUpdated
  167. //----------------------------------------------------------------------------------------
  168.  
  169. void FW_CLinkDestination::LinkUpdated(Environment* ev, ODUpdateID id)
  170. {
  171.     ODLinkKey linkKey;
  172.     if (!fODLink->Lock(ev, 0, &linkKey)) 
  173.         return;
  174.  
  175.     /* The following Try-block is for when OpenDoc throws an exception in GetContentStorageUnit.
  176.        If a cross-document link was just created, LinkUpdated gets called before the link content SU 
  177.        has received any data. In that case we want to just let the exception fall on the floor.
  178.        LinkUpdated will be called again after the link data has been written.
  179.     */
  180.     ODStorageUnit* su;
  181.     FW_VOLATILE(linkKey);
  182.     FW_TRY
  183.     {
  184.         su = fODLink->GetContentStorageUnit(ev, linkKey); /* cross-doc link will fail the 1st time */
  185.     }
  186.     FW_CATCH_BEGIN
  187.     FW_CATCH_REFERENCE(FW_XException, ex)
  188.     {
  189.         fODLink->Unlock(ev, linkKey);
  190.         // If GetContentStorageUnit returned the error kODErrNoLinkContent,
  191.         // the last source update failed; don't update the link at this time.
  192.         if (ex.GetPlatformError() == kODErrNoLinkContent)
  193.             return;
  194.         FW_THROW_SAME();
  195.     }
  196.     FW_CATCH_END
  197.  
  198.     FW_Boolean updateSuccessful = false;
  199.     FW_TRY
  200.     {
  201.         if (this->DoUpdateLink(ev, su, fEmbed ? &fEmbedInfo : NULL))    // part-specific
  202.         {
  203.             // --- Update the link info ---
  204.             fLinkInfo.change = id;
  205.             fLinkInfo.changeTime = fODLink->GetChangeTime(ev);
  206.             updateSuccessful = true;
  207.         }
  208.         else                            // Couldn't update the link, for some reason
  209.             if (!fEstablished)
  210.                 FW_THROW(FW_XException(kODErrCannotEstablishLink));
  211.     }
  212.     FW_CATCH_BEGIN
  213.     FW_CATCH_EVERYTHING()
  214.     {
  215.         // error occurred in DoUpdateLink somewhere
  216.         fODLink->Unlock(ev, linkKey);
  217.         FW_THROW_SAME();
  218.     }
  219.     FW_CATCH_END
  220.  
  221.     // --- We're done with the link content SU ---
  222.     fODLink->Unlock(ev, linkKey);
  223.  
  224.     if (!fEstablished)    // first update must have failed
  225.         this->PrivEstablishLink(ev);
  226.     
  227.     // --- Propagate changes to source links maintained by the part ---
  228.     if (updateSuccessful)
  229.         this->DoPropagateChanges(ev, id);
  230. }
  231.  
  232. //----------------------------------------------------------------------------------------
  233. //    FW_CLinkDestination::DoPropagateChanges
  234. //----------------------------------------------------------------------------------------
  235. void FW_CLinkDestination::DoPropagateChanges(Environment* ev, ODUpdateID updateID)
  236. {
  237.     // Content in the specified destination link has changed.
  238.     // Override to propagate changes to source links maintained by this part (part-specific)
  239.  
  240.     // --- Notify all containing parts of the change ---
  241.     fPresentation->ContentUpdated(ev, updateID);
  242.  
  243.     fPresentation->Invalidate(ev);    // force all frames to be redrawn
  244. }
  245.  
  246. //----------------------------------------------------------------------------------------
  247. //    FW_CLinkDestination::Register
  248. //----------------------------------------------------------------------------------------
  249. void FW_CLinkDestination::Register(Environment* ev, FW_CPart* itsPart)
  250. {
  251.     ODUpdateID linkUpdateID = fODLink->GetUpdateID(ev);
  252.     FW_Boolean needsUpdate = (fLinkInfo.change != linkUpdateID);
  253.  
  254.     if (fLinkInfo.autoUpdate)
  255.     {
  256.         //--- Register for automatic updates ---
  257.         // First determine if another link with the same ODLink as ours already registered
  258.         FW_Boolean alreadyRegistered = FALSE;
  259.         FW_CPartLinkDestIterator iter(itsPart);
  260.         for (FW_CLinkDestination* link = iter.First(); iter.IsNotComplete(); link = iter.Next())
  261.         {
  262.             if ((link != this) && fODLink->IsEqualTo(ev, link->GetODLink(ev))
  263.                 && link->IsRegistered(ev))
  264.             {
  265.                 alreadyRegistered = TRUE;
  266.                 break;
  267.             }
  268.         }
  269.         if (!alreadyRegistered)
  270.         {
  271.             fODLink->RegisterDependent(ev, itsPart->GetODPart(ev), fLinkInfo.change);
  272.             // part::LinkUpdated call will be generated
  273.             needsUpdate = FALSE;
  274.         }
  275.         fRegistered = TRUE;
  276.         itsPart->GetODPart(ev)->Acquire(ev);
  277.         fPart = itsPart;    // remember which part we're registered to, so we can Unregister
  278.     }
  279.  
  280.     if (needsUpdate)    // Manually update now
  281.         this->LinkUpdated(ev, linkUpdateID);
  282. }
  283.  
  284. //----------------------------------------------------------------------------------------
  285. //    FW_CLinkDestination::Unregister
  286. //----------------------------------------------------------------------------------------
  287. void FW_CLinkDestination::Unregister(Environment* ev)
  288. {
  289.     if (!fRegistered) return;
  290.  
  291.     if (fLinkInfo.autoUpdate)
  292.     {
  293.         // Unregister, if this is the last automatically updated destination of the link in the part
  294.         FW_ASSERT(fPart);
  295.         short autoCount = 0;
  296.         FW_CPartLinkDestIterator iter(fPart);
  297.         for (FW_CLinkDestination* link = iter.First(); iter.IsNotComplete(); link = iter.Next())
  298.         {
  299.             if (link->IsAutoUpdate(ev) && fODLink->IsEqualTo(ev, link->GetODLink(ev)))
  300.                 autoCount++;
  301.         }
  302.         if (autoCount == 1)    // this is the only registered link
  303.         {
  304.             fODLink->UnregisterDependent(ev, fPart->GetODPart(ev));
  305.         }
  306.     }
  307.  
  308.     if (fPart)
  309.     {
  310.         fPart->GetODPart(ev)->Release(ev);
  311.         fPart = NULL;    
  312.     }
  313.  
  314.     fRegistered = FALSE;
  315. }
  316.  
  317. //---------------------------------------------------------------------------------------
  318. //    FW_CLinkDestination::BreakLink
  319. //----------------------------------------------------------------------------------------
  320. void FW_CLinkDestination::BreakLink(Environment* ev)
  321. {
  322.     this->Unregister(ev);
  323.     fEstablished = false;
  324. }
  325.  
  326. //---------------------------------------------------------------------------------------
  327. //    FW_CLinkDestination::RestoreLink
  328. //----------------------------------------------------------------------------------------
  329. void FW_CLinkDestination::RestoreLink(Environment* ev, FW_CPart* part)
  330. {
  331.     fLinkInfo.change = kODUnknownUpdate;
  332.  
  333.     // Re-register the link if necessary
  334.     this->Register(ev, part);
  335. }
  336.  
  337. //---------------------------------------------------------------------------------------
  338. //    FW_CLinkDestination::ExternalizeLink
  339. //----------------------------------------------------------------------------------------
  340. void FW_CLinkDestination::ExternalizeLink(Environment* ev, ODStorageUnit* storageUnit,
  341.                                           FW_CCloneInfo* cloneInfo)
  342. {
  343.     //-- Storage unit must be focused to property kODPropContents, value destLinkFormat
  344.     ODStorageUnitRef suRef;
  345.     fODLink->Externalize(ev);
  346.  
  347.     ODID linkID = fODLink->GetID(ev);
  348.     if (cloneInfo != NULL)
  349.     {
  350.         linkID = cloneInfo->Clone(ev, linkID, 0, 0);
  351.     }
  352.  
  353.     // May not have been able to clone the link
  354.     if (linkID == kODNULL) return;
  355.  
  356.     //--- Write the link version number ---
  357.     long version = FW_kLinkVersionNumber;
  358.     FW_CByteArray byteArray(&version, sizeof(long));
  359.     storageUnit->SetValue(ev, byteArray);
  360.  
  361.     //--- Write a reference to the link ---
  362.     storageUnit->GetStrongStorageUnitRef(ev, linkID, suRef);
  363.     byteArray.Set(&suRef, sizeof(ODStorageUnitRef));
  364.     storageUnit->SetValue(ev, byteArray);
  365.  
  366.     //--- Write link info ---
  367.     ODType savedKind = fLinkInfo.kind;            // save kind string
  368.     fLinkInfo.kind = (ODType) strlen(savedKind) + 1;
  369.     byteArray.Set(&fLinkInfo, sizeof(ODLinkInfo));
  370.     storageUnit->SetValue(ev, byteArray);        // write out linkinfo
  371.     byteArray.Set((void*)savedKind, (ODULong)fLinkInfo.kind);
  372.     storageUnit->SetValue(ev, byteArray);        // write out kind string
  373.     fLinkInfo.kind = savedKind;                    // restore kind string
  374.     
  375.     //--- Write embed info, if any ---
  376.     byteArray.Set(&fEmbed, sizeof(FW_Boolean));
  377.     storageUnit->SetValue(ev, byteArray);
  378.     if (fEmbed)
  379.     {
  380.         //-- save strings, except for selectedKind, which was written above
  381.         savedKind = fEmbedInfo.translateKind;        // save translateKind string
  382.         if (savedKind != NULL)
  383.             fEmbedInfo.translateKind = (ODType) strlen(savedKind) + 1;
  384.         ODEditor savedEditor = fEmbedInfo.editor;    // save editor string
  385.         if (savedEditor != NULL)
  386.             fEmbedInfo.editor = (ODType) strlen(savedEditor) + 1;
  387.  
  388.         //-- write fields of fEmbedInfo
  389.         byteArray.Set(&fEmbedInfo, sizeof(ODPasteAsResult));
  390.         storageUnit->SetValue(ev, byteArray);
  391.         if (savedKind != NULL)                        // write the translateKind string
  392.         {
  393.             byteArray.Set((void*)savedKind, (ODULong)fEmbedInfo.translateKind);
  394.             storageUnit->SetValue(ev, byteArray);
  395.         }
  396.         if (savedEditor != NULL)                    // write the editor string
  397.         {
  398.             byteArray.Set((void*)savedEditor, (ODULong)fEmbedInfo.editor);
  399.             storageUnit->SetValue(ev, byteArray);
  400.         }
  401.  
  402.         //-- Restore string ptrs to fEmbedInfo
  403.         fEmbedInfo.translateKind = savedKind;
  404.         fEmbedInfo.editor = savedEditor;
  405.     }
  406.  
  407.     //--- Write out data specific to this part's link ---
  408.     this->DoExternalizeLink(ev, storageUnit, cloneInfo);
  409. }
  410.  
  411. //---------------------------------------------------------------------------------------
  412. //    FW_CLinkDestination::SavePasteAsSettings
  413. //----------------------------------------------------------------------------------------
  414. void FW_CLinkDestination::SavePasteAsSettings(Environment* ev, ODPasteAsResult& pasteAsResult)
  415. {
  416. FW_UNUSED(ev);
  417.     // Record the PasteAs dialog settings, so links can be updated appropriately
  418.     fLinkInfo.kind = pasteAsResult.selectedKind;    // Copy the pointer
  419.     fEmbed = (pasteAsResult.mergeSetting == kODFalse);
  420.     if (fEmbed)
  421.     {
  422.         // Embed As: remember the user's settings
  423.         fEmbedInfo = pasteAsResult;
  424.         // Set pointer fields to NULL so they won't be disposed by the caller
  425.         pasteAsResult.translateKind = NULL;
  426.         pasteAsResult.editor = NULL;
  427.     }
  428.  
  429.     pasteAsResult.selectedKind = NULL;                // so caller doesn't dispose it
  430. }
  431.  
  432.